﻿using UnityEngine;

namespace Core
{
    public static partial class Utils
    {
        public static class Noise
        {
            /// <summary>
            /// 分形布朗运动函数
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <param name="oct">八度</param>
            /// <param name="frequency">频率</param>
            /// <param name="amplitude">振幅</param>
            /// <param name="lacunarity">间隙度，影响频率</param>
            /// <param name="persistance">持续性，影响振幅</param>
            /// <returns></returns>
            // ReSharper disable once InconsistentNaming
            public static float FBM(float x, float y, int oct,
                float frequency = 1, float amplitude = 1,
                float lacunarity = 2, float persistance = 2)
            {
                float total = 0;
                float maxValue = 0;
                for (int i = 0; i < oct; i++)
                {
                    //通过循环叠加噪声
                    total += Mathf.PerlinNoise(x * frequency, y * frequency) * amplitude;

                    //最大值是每个oct使用的振幅相加
                    maxValue += amplitude;

                    //以一定的比例降低噪声的振幅
                    amplitude /= persistance;

                    //以一定的倍数连续升高频率
                    frequency *= lacunarity;
                }

                //注意返回值降到0-1之间的范围内
                return total / maxValue;
            }

            /// <summary>
            /// 边缘下沉
            /// </summary>
            /// <param name="size"></param>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public static float SinkEdge(int size, int x, int y)
            {
                float i = x / (float)size * 2 - 1;
                float j = y / (float)size * 2 - 1;

                var value = Mathf.Max(Mathf.Abs(i), Mathf.Abs(j));

                return Evaluate2(value);
            }

            public static float UpCenter(int size, int x, int y)
            {
                float i = x / (float)size * 2 - 1;
                float j = y / (float)size * 2 - 1;

                var len = new Vector2(i, j).magnitude;

                var x_pi = len * Mathf.PI;
                var v = Mathf.Sin(x_pi) / x_pi;
                return 0.5f - v;
            }

            public static float DisToCenter(int x, int y, int size)
            {
                float i = x / (float)size * 2 - 1;
                float j = y / (float)size * 2 - 1;

                var dis = new Vector2(i, j).magnitude;

                return dis;
            }

            // ReSharper disable once UnusedMember.Local
            private static float Evaluate(float value)
            {
                return Mathf.Pow(value, 3);
            }

            // ReSharper disable once UnusedMember.Local
            private static float Evaluate1(float value)
            {
                float a = 3f;
                float b = 2.2f;
                var va = Mathf.Pow(value, a);
                var vb = Mathf.Pow(b - b * value, a);
                return va / (va + vb);
            }

            private static float Evaluate2(float value)
            {
                var t = 0.8f;
                if (value < t)
                {
                    return 0;
                }
                return (value - t) / (1 - t);
            }
        }
    }
}
